package com.gitee.qdbp.able.jdbc.condition;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.gitee.qdbp.able.beans.Copyable;
import com.gitee.qdbp.able.enums.LogicType;
import com.gitee.qdbp.able.enums.MatchType;
import com.gitee.qdbp.able.jdbc.base.DbCondition;
import com.gitee.qdbp.able.jdbc.base.LogicCondition;
import com.gitee.qdbp.able.jdbc.base.MatchCondition;
import com.gitee.qdbp.able.jdbc.base.WhereCondition;
import com.gitee.qdbp.able.jdbc.model.LikeValue;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 数据库Where条件容器<br>
 * <pre>
    DbWhere where = new DbWhere();
    // [SQL] AND ID = :$1
    where.andEquals("id", entity.getId());
    // [SQL] AND ID != :$1
    where.andNotEquals("id", entity.getId());
    // [SQL] AND CREATE_TIME > :$1
    where.andGreaterThen("createTime", new Date());
    // [SQL] AND CREATE_TIME >= :$1
    where.andGreaterEqualsThen("createTime", new Date());
    // [SQL] AND CREATE_TIME < :$1
    where.andLessThen("createTime", new Date());
    // [SQL] AND CREATE_TIME <= :$1
    where.andLessEqualsThen("createTime", new Date());
    // [SQL] AND USER_STATE IS NULL
    where.andIsNull("userState");
    // [SQL] AND USER_STATE IS NOT NULL
    where.andIsNotNull("userState");
    // [ORACLE/DB2] AND USER_NAME LIKE('%'||:$1||'%')
    // [MYSQL] AND USER_NAME LIKE CONCAT('%',:$1,'%')
    where.andLike("userName", entity.getUserName());
    // [ORACLE/DB2] AND USER_NAME NOT LIKE('%'||:$1||'%')
    // [MYSQL] AND USER_NAME NOT LIKE CONCAT('%',:$1,'%')
    where.andNotLike("userName", entity.getUserName());
    // [ORACLE/DB2] AND PHONE LIKE(:$1||'%')
    // [MYSQL] AND PHONE LIKE CONCAT(:$1,'%')
    where.andStarts("phone", "139");
    // [ORACLE/DB2] AND PHONE LIKE('%'||:$1)
    // [MYSQL] AND PHONE LIKE CONCAT('%',:$1)
    where.andEnds("phone", "8888");
    // [SQL] AND USER_STATE IN (:$1, :$2, ...)
    where.andIn("userState", UserState.NORMAL, UserState.LOCKED, ...);
    // [SQL] AND USER_STATE NOT IN (:$1, :$2, ...)
    where.andNotIn("userState", UserState.NORMAL, UserState.LOCKED, ...);
    // [SQL] AND CREATE_TIME BETWEEN :$1 AND :$2
    where.andBetween("createTime", entity.getStartTime(), entity.getEndTime());
    // [SQL] AND ( USER_NAME LIKE '%'||:$1||'%' OR REAL_NAME LIKE '%'||:$2||'%' )
    where.andSubCondition(new SubCondition() { // 子条件
        public void build(DbWhere w) {
            w.orLike("userName", entity.getKeyword())
                .orLike("realName", entity.getKeyword());
        }
    });
    // JDK8
    where.andSubCondition((w) -> { // 子条件
        w.orLike("userName", entity.getKeyword())
            .orLike("realName", entity.getKeyword());
    });
 * </pre>
 *
 * @author zhaohuihua
 * @version 181221
 */
public class DbWhere extends DbItems implements Copyable {

    /** SerialVersionUID **/
    private static final long serialVersionUID = 1L;

    /** 没有查询条件的空Where **/
    public static final DbWhere NONE = new ReadonlyWhere();

    /**
     * Where条件<br>
     * 字段名可以带表别名, 如where.on("u.id", "=", entity.getId());<br>
     * 
     * @param fieldName 字段名称
     * @param operate 目前支持如下操作:<br>
     *            =, !=, &lt;, &lt;=, &gt;, &gt;=, <br>
     *            Equals(equals), NotEquals(not equals), <br>
     *            LessThen(less then), LessEqualsThen(less equals then), <br>
     *            GreaterThen(greater then), GreaterEqualsThen(greater equals then), <br>
     *            IsNull(is null), IsNotNull(is not null), <br>
     *            Like(like), NotLike(not like), <br>
     *            Starts(starts), NotStarts(not starts), Ends(ends), NotEnds(not ends), <br>
     *            In(in), NotIn(not in), Between(between), NotBetween(not between)
     * @param fieldValues 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere on(String fieldName, String operate, Object... fieldValues) {
        return this.and(fieldName, operate, fieldValues);
    }

    /** 增加自定义条件 **/
    public DbWhere on(WhereCondition condition) {
        super.put(condition);
        return this;
    }

    /**
     * AND查询条件
     * 
     * @param fieldName 字段名称
     * @param operate 操作符
     * @param fieldValues 字段值
     * @return 返回容器自身, 用于链式操作
     */
    protected DbWhere and(String fieldName, String operate, Object... fieldValues) {
        DbField condition = parseField(LogicType.AND, fieldName, operate, fieldValues);
        this.put(condition);
        return this;
    }

    /**
     * OR查询条件
     * 
     * @param fieldName 字段名称
     * @param operate 操作符
     * @param fieldValues 字段值
     * @return 返回容器自身, 用于链式操作
     */
    protected DbWhere or(String fieldName, String operate, Object... fieldValues) {
        DbField condition = parseField(LogicType.OR, fieldName, operate, fieldValues);
        this.put(condition);
        return this;
    }

    /**
     * AND查询条件
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名称
     * @param operate 操作符
     * @param fieldValues 字段值
     * @return 返回容器自身, 用于链式操作
     */
    protected DbWhere andIf(boolean asserts, String fieldName, String operate, Object... fieldValues) {
        if (asserts) {
            DbField condition = parseField(LogicType.AND, fieldName, operate, fieldValues);
            this.put(condition);
        }
        return this;
    }

    /**
     * OR查询条件
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名称
     * @param operate 操作符
     * @param fieldValues 字段值
     * @return 返回容器自身, 用于链式操作
     */
    protected DbWhere orIf(boolean asserts, String fieldName, String operate, Object... fieldValues) {
        if (asserts) {
            DbField condition = parseField(LogicType.OR, fieldName, operate, fieldValues);
            this.put(condition);
        }
        return this;
    }

    /**
     * 增加条件
     * 
     * @param condition 条件
     */
    @Override
    protected void put(DbField condition) {
        VerifyTools.requireNonNull(condition, "condition");
        if (condition instanceof Field) {
            super.put(condition);
        } else {
            super.put(new Field(LogicType.AND, condition));
        }
    }

    /**
     * 增加条件
     * 
     * @param condition 自定义条件
     */
    @Override
    protected void put(DbCondition condition) {
        VerifyTools.requireNonNull(condition, "condition");
        if (condition instanceof Field) {
            super.put(condition);
        } else if (condition instanceof DbField) {
            super.put(new Field(LogicType.AND, (DbField) condition));
        } else {
            super.put(condition);
        }
    }

    protected Field parseField(LogicType logicType, String fieldName, String operate, Object... fieldValues) {
        VerifyTools.nvl(fieldName, "fieldName");
        Field condition = new Field(logicType);
        condition.setFieldName(fieldName);
        condition.setOperateType(operate);
        if (fieldValues != null && fieldValues.length > 0) {
            if (fieldValues.length == 1) {
                condition.setFieldValue(fieldValues[0]);
            } else {
                condition.setFieldValue(fieldValues);
            }
        }
        return condition;
    }

    /**
     * 创建子查询条件
     * 
     * @param logicType 逻辑类型 AND/OR 这里指的是容器内部子条件项之间默认的连接类型
     * @return 子查询条件容器
     * @deprecated 这里的逻辑类型并不是此容器的连接类型<br>
     *             而是容器内部子条件项之间使用on()方法时使用的连接类型, 不符合一般理解<br>
     *             改为{@link #andSubCondition(SubCondition)}<br>
     *             {@link #andNotSubCondition(SubCondition)}<br>
     *             {@link #orSubCondition(SubCondition)}<br>
     *             {@link #orNotSubCondition(SubCondition)}<br>
     */
    @Deprecated
    public SubWhere sub(String logicType) {
        return this.sub(logicType, true);
    }

    /**
     * 创建子查询条件容器
     * 
     * @param logicType 逻辑类型 AND/OR 这里指的是容器内部子条件项之间默认的连接类型
     * @param positive 匹配模式 肯定模式还是否定模式
     * @return 子查询条件容器
     * @deprecated 这里的逻辑类型并不是此容器的连接类型<br>
     *             而是容器内部子条件项之间使用on()方法时使用的连接类型, 不符合一般理解<br>
     *             改为{@link #andSubCondition(SubCondition)}<br>
     *             {@link #andNotSubCondition(SubCondition)}<br>
     *             {@link #orSubCondition(SubCondition)}<br>
     *             {@link #orNotSubCondition(SubCondition)}<br>
     */
    @Deprecated
    public SubWhere sub(String logicType, boolean positive) {
        VerifyTools.nvl(logicType, "logicType");
        LogicType innerLogicType;
        if ("AND".equalsIgnoreCase(logicType)) {
            innerLogicType = LogicType.AND;
        } else if ("OR".equalsIgnoreCase(logicType)) {
            innerLogicType = LogicType.OR;
        } else {
            String msg = "Unsupported logic type: " + logicType + ". acceptable values are: 'AND', 'OR'.";
            throw new IllegalArgumentException(msg);
        }
        MatchType matchType = positive ? MatchType.Positive : MatchType.Negative;
        SubWhere sub = new InnerSubWhere(this, LogicType.AND, matchType, innerLogicType);
        this.put(sub);
        return sub;
    }

    /**
     * 克隆为新对象(如果子类有新增字段或没有默认构造函数就应该覆盖该方法)
     * 
     * @return 新对象
     * @since 5.0.0
     */
    @Override
    public DbWhere copy() {
        DbWhere copies = newCopies();
        this.copyTo(copies);
        return copies;
    }

    protected void copyTo(DbWhere copies) {
        Iterator<DbCondition> iterator = this.iterator();
        while (iterator.hasNext()) {
            DbCondition item = iterator.next();
            if (item instanceof Field) {
                copies.put(((Field) item).copy());
            } else if (item instanceof DbField) {
                copies.put(((DbField) item).copy());
            } else if (item instanceof SubWhere) {
                copies.put(((SubWhere) item).copy().setParent(copies));
            } else if (item instanceof DbWhere) {
                copies.put(((DbWhere) item).copy());
            } else if (item instanceof Copyable) {
                DbCondition newer = (DbCondition) ((Copyable) item).copy();
                copies.put(newer);
            } else { // DbCondition/DbConditions
                copies.put(item); // 无法克隆为副本
            }
        }
    }

    /**
     * 创建副本对象(如果子类没有默认构造函数就应该覆盖该方法)
     * 
     * @return 副本对象
     * @since 5.0.0
     */
    protected DbWhere newCopies() {
        if (this.getClass() == DbWhere.class) { // 当前类
            return new DbWhere();
        } else { // 子类
            try {
                return this.getClass().newInstance();
            } catch (Exception e) {
                throw new IllegalStateException("CloneNotSupported, FailedToInvokeDefaultConstructor.");
            }
        }
    }

    /**
     * 根据字段名称替换条件
     * 
     * @param fieldName 字段名称
     * @return 替换了几个条件
     */
    public int replace(String fieldName, String operate, Object... fieldValues) {
        DbField condition = parseField(null, fieldName, operate, fieldValues);
        int count = this.replace(condition);
        if (count == 0) {
            this.put(condition);
            count++;
        }
        return count;
    }

    /**
     * 等于条件<br>
     * [SQL] AND fieldName = fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andEquals(String fieldName, Object fieldValue) {
        return this.and(fieldName, "=", fieldValue);
    }

    /**
     * 不等于条件<br>
     * [SQL] AND fieldName != fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotEquals(String fieldName, Object fieldValue) {
        return this.and(fieldName, "!=", fieldValue);
    }

    /**
     * 小于条件<br>
     * [SQL] AND fieldName < fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLessThen(String fieldName, Object fieldValue) {
        return this.and(fieldName, "<", fieldValue);
    }

    /**
     * 小于等于条件<br>
     * [SQL] AND fieldName <= fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLessEqualsThen(String fieldName, Object fieldValue) {
        return this.and(fieldName, "<=", fieldValue);
    }

    /**
     * 大于条件<br>
     * [SQL] AND fieldName > fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andGreaterThen(String fieldName, Object fieldValue) {
        return this.and(fieldName, ">", fieldValue);
    }

    /**
     * 大于等于条件<br>
     * [SQL] AND fieldName >= fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andGreaterEqualsThen(String fieldName, Object fieldValue) {
        return this.and(fieldName, ">=", fieldValue);
    }

    /**
     * IS NULL条件<br>
     * [SQL] AND fieldName IS NULL
     * 
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIsNull(String fieldName) {
        return this.and(fieldName, "is null");
    }

    /**
     * IS NOT NULL条件<br>
     * [SQL] AND fieldName IS NOT NULL
     * 
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIsNotNull(String fieldName) {
        return this.and(fieldName, "is not null");
    }

    /**
     * LIKE条件<br>
     * [ORACLE/DB2] AND fieldName LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] AND fieldName LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找带有%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLike(String, LikeValue)
     */
    public DbWhere andLike(String fieldName, String fieldValue) {
        return this.and(fieldName, "like", fieldValue);
    }

    /**
     * LIKE条件<br>
     * AND fieldName LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: andLike("code", new LikeValue('#', "%10#%"));表示查找以10%结尾的数据<br>
     * 如: andLike("code", new LikeValue("%HOT%COOL%"));表示查找含有HOT和COOL的数据<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLike(String fieldName, LikeValue fieldValue) {
        return this.and(fieldName, "like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不包含%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLike(String, LikeValue)
     */
    public DbWhere andNotLike(String fieldName, String fieldValue) {
        return this.and(fieldName, "not like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * AND fieldName NOT LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: andNotLike("code", new LikeValue('#', "%10#%"));表示查找不以10%结尾的数据<br>
     * 如: andNotLike("code", new LikeValue("%HOT%COOL%"));表示查找不含有HOT和COOL的数据<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotLike(String fieldName, LikeValue fieldValue) {
        return this.and(fieldName, "not like", fieldValue);
    }

    /**
     * LIKE前缀查询条件<br>
     * [ORACLE/DB2] AND fieldName LIKE(fieldValue||'%')<br>
     * [MYSQL] AND fieldName LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLike(String, LikeValue)
     */
    public DbWhere andStarts(String fieldName, String fieldValue) {
        return this.and(fieldName, "starts", fieldValue);
    }

    /**
     * NOT LIKE前缀查询条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE(fieldValue||'%')<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLike(String, LikeValue)
     */
    public DbWhere andNotStarts(String fieldName, String fieldValue) {
        return this.and(fieldName, "not starts", fieldValue);
    }

    /**
     * LIKE后缀查询条件<br>
     * [ORACLE/DB2] AND fieldName LIKE('%'||fieldValue)<br>
     * [MYSQL] AND fieldName LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLike(String, LikeValue)
     */
    public DbWhere andEnds(String fieldName, String fieldValue) {
        return this.and(fieldName, "ends", fieldValue);
    }

    /**
     * NOT LIKE后缀查询条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE('%'||fieldValue)<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLike(String, LikeValue)
     */
    public DbWhere andNotEnds(String fieldName, String fieldValue) {
        return this.and(fieldName, "not ends", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] AND fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIn(String fieldName, Collection<?> fieldValue) {
        return this.and(fieldName, "in", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] AND fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIn(String fieldName, Object... fieldValue) {
        return this.and(fieldName, "in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] AND fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotIn(String fieldName, Collection<?> fieldValue) {
        return this.and(fieldName, "not in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] AND fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotIn(String fieldName, Object... fieldValue) {
        return this.and(fieldName, "not in", fieldValue);
    }

    /**
     * BETWEEN查询条件<br>
     * [SQL] AND fieldName BETWEEN startValue AND endValue
     * 
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andBetween(String fieldName, Object startValue, Object endValue) {
        return this.and(fieldName, "between", startValue, endValue);
    }

    /**
     * NOT BETWEEN查询条件<br>
     * [SQL] AND fieldName NOT BETWEEN startValue AND endValue
     * 
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotBetween(String fieldName, Object startValue, Object endValue) {
        return this.and(fieldName, "not between", startValue, endValue);
    }

    /**
     * 子查询条件<pre>
    // [SQL] AND ( USER_NAME LIKE '%'||keyword||'%' OR REAL_NAME LIKE '%'||keyword||'%' )
    where.andSubCondition(new SubCondition() { // 子条件
        public void build(DbWhere w) {
            w.orLike("userName", entity.getKeyword())
                .orLike("realName", entity.getKeyword());
        }
    });
    // JDK8
    where.andSubCondition((w) -> { // 子条件
        w.orLike("userName", entity.getKeyword())
            .orLike("realName", entity.getKeyword());
    });</pre>
     * 
     * @param condition 条件构造器
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andSubCondition(SubCondition condition) {
        SubWhere where = new SubWhere(this, LogicType.AND, MatchType.Positive);
        this.put(where);
        condition.build(where);
        return this;
    }

    /**
     * 否定子查询条件<pre>
    // [SQL] AND NOT ( USER_NAME LIKE '%'||keyword||'%' OR REAL_NAME LIKE '%'||keyword||'%' )
    where.andNotSubCondition(new SubCondition() { // 子条件
        public void build(DbWhere w) {
            w.orLike("userName", entity.getKeyword())
                .orLike("realName", entity.getKeyword());
        }
    });
    // JDK8
    where.andNotSubCondition((w) -> { // 子条件
        w.orLike("userName", entity.getKeyword())
            .orLike("realName", entity.getKeyword());
    });</pre>
     * 
     * @param condition 条件构造器
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotSubCondition(SubCondition condition) {
        SubWhere where = new SubWhere(this, LogicType.AND, MatchType.Negative);
        this.put(where);
        condition.build(where);
        return this;
    }

    /**
     * 自定义查询条件
     * 
     * @param condition 条件对象
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andBizCondition(WhereCondition condition) {
        BizCondition bizCondition = new BizCondition(condition, LogicType.AND, MatchType.Positive);
        super.put(bizCondition);
        return this;
    }

    /**
     * 自定义查询条件
     * 
     * @param condition 条件对象
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotBizCondition(WhereCondition condition) {
        BizCondition bizCondition = new BizCondition(condition, LogicType.AND, MatchType.Negative);
        super.put(bizCondition);
        return this;
    }

    /**
     * 等于条件<br>
     * [SQL] OR fieldName = fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orEquals(String fieldName, Object fieldValue) {
        return this.or(fieldName, "=", fieldValue);
    }

    /**
     * 不等于条件<br>
     * [SQL] OR fieldName != fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotEquals(String fieldName, Object fieldValue) {
        return this.or(fieldName, "!=", fieldValue);
    }

    /**
     * 小于条件<br>
     * [SQL] OR fieldName < fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLessThen(String fieldName, Object fieldValue) {
        return this.or(fieldName, "<", fieldValue);
    }

    /**
     * 小于等于条件<br>
     * [SQL] OR fieldName <= fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLessEqualsThen(String fieldName, Object fieldValue) {
        return this.or(fieldName, "<=", fieldValue);
    }

    /**
     * 大于条件<br>
     * [SQL] OR fieldName > fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orGreaterThen(String fieldName, Object fieldValue) {
        return this.or(fieldName, ">", fieldValue);
    }

    /**
     * 大于等于条件<br>
     * [SQL] OR fieldName >= fieldValue
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orGreaterEqualsThen(String fieldName, Object fieldValue) {
        return this.or(fieldName, ">=", fieldValue);
    }

    /**
     * IS NULL条件<br>
     * [SQL] OR fieldName IS NULL
     * 
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIsNull(String fieldName) {
        return this.or(fieldName, "is null");
    }

    /**
     * IS NOT NULL条件<br>
     * [SQL] OR fieldName IS NOT NULL
     * 
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIsNotNull(String fieldName) {
        return this.or(fieldName, "is not null");
    }

    /**
     * LIKE条件<br>
     * [ORACLE/DB2] OR fieldName LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] OR fieldName LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找带有%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLike(String, LikeValue)
     */
    public DbWhere orLike(String fieldName, String fieldValue) {
        return this.or(fieldName, "like", fieldValue);
    }

    /**
     * LIKE条件<br>
     * OR fieldName LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: orLike("code", new LikeValue('#', "%10#%"));表示查找以10%结尾的数据<br>
     * 如: orLike("code", new LikeValue("%HOT%COOL%"));表示查找含有HOT和COOL的数据<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLike(String fieldName, LikeValue fieldValue) {
        return this.or(fieldName, "like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不包含%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLike(String, LikeValue)
     */
    public DbWhere orNotLike(String fieldName, String fieldValue) {
        return this.or(fieldName, "not like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * OR fieldName NOT LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: orNotLike("code", new LikeValue('#', "%10#%"));表示查找不以10%结尾的数据<br>
     * 如: orNotLike("code", new LikeValue("%HOT%COOL%"));表示查找不含有HOT和COOL的数据<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotLike(String fieldName, LikeValue fieldValue) {
        return this.or(fieldName, "not like", fieldValue);
    }

    /**
     * LIKE前缀查询条件<br>
     * [ORACLE/DB2] OR fieldName LIKE(fieldValue||'%')<br>
     * [MYSQL] OR fieldName LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLike(String, LikeValue)
     */
    public DbWhere orStarts(String fieldName, String fieldValue) {
        return this.or(fieldName, "starts", fieldValue);
    }

    /**
     * NOT LIKE前缀查询条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE(fieldValue||'%')<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLike(String, LikeValue)
     */
    public DbWhere orNotStarts(String fieldName, String fieldValue) {
        return this.or(fieldName, "not starts", fieldValue);
    }

    /**
     * LIKE后缀查询条件<br>
     * [ORACLE/DB2] OR fieldName LIKE('%'||fieldValue)<br>
     * [MYSQL] OR fieldName LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLike(String, LikeValue)
     */
    public DbWhere orEnds(String fieldName, String fieldValue) {
        return this.or(fieldName, "ends", fieldValue);
    }

    /**
     * NOT LIKE后缀查询条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE('%'||fieldValue)<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLike(String, LikeValue)}方法<br>
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLike(String, LikeValue)
     */
    public DbWhere orNotEnds(String fieldName, String fieldValue) {
        return this.or(fieldName, "not ends", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] OR fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIn(String fieldName, Collection<?> fieldValue) {
        return this.or(fieldName, "in", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] OR fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIn(String fieldName, Object... fieldValue) {
        return this.or(fieldName, "in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] OR fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotIn(String fieldName, Collection<?> fieldValue) {
        return this.or(fieldName, "not in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] OR fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotIn(String fieldName, Object... fieldValue) {
        return this.or(fieldName, "not in", fieldValue);
    }

    /**
     * BETWEEN查询条件<br>
     * [SQL] OR fieldName BETWEEN startValue AND endValue
     * 
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orBetween(String fieldName, Object startValue, Object endValue) {
        return this.or(fieldName, "between", startValue, endValue);
    }

    /**
     * NOT BETWEEN查询条件<br>
     * [SQL] OR fieldName NOT BETWEEN startValue AND endValue
     * 
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotBetween(String fieldName, Object startValue, Object endValue) {
        return this.or(fieldName, "not between", startValue, endValue);
    }

    /**
     * 子查询条件<pre>
    // [SQL] OR ( USER_NAME LIKE '%'||keyword||'%' OR REAL_NAME LIKE '%'||keyword||'%' )
    where.orSubCondition(new SubCondition() { // 子条件
        public void build(DbWhere w) {
            w.orLike("userName", entity.getKeyword())
                .orLike("realName", entity.getKeyword());
        }
    });
    // JDK8
    where.orSubCondition((w) -> { // 子条件
        w.orLike("userName", entity.getKeyword())
            .orLike("realName", entity.getKeyword());
    });</pre>
     * 
     * @param condition 条件构造器
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orSubCondition(SubCondition condition) {
        SubWhere where = new SubWhere(this, LogicType.OR, MatchType.Positive);
        this.put(where);
        condition.build(where);
        return this;
    }

    /**
     * 否定子查询条件<pre>
    // [SQL] OR NOT ( USER_NAME LIKE '%'||keyword||'%' OR REAL_NAME LIKE '%'||keyword||'%' )
    where.orNotSubCondition(new SubCondition() { // 子条件
        public void build(DbWhere w) {
            w.orLike("userName", entity.getKeyword())
                .orLike("realName", entity.getKeyword());
        }
    });
    // JDK8
    where.orNotSubCondition((w) -> { // 子条件
        w.orLike("userName", entity.getKeyword())
            .orLike("realName", entity.getKeyword());
    });</pre>
     * 
     * @param condition 条件构造器
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotSubCondition(SubCondition condition) {
        SubWhere where = new SubWhere(this, LogicType.OR, MatchType.Negative);
        this.put(where);
        condition.build(where);
        return this;
    }

    /**
     * 自定义查询条件
     * 
     * @param condition 条件对象
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orBizCondition(WhereCondition condition) {
        BizCondition bizCondition = new BizCondition(condition, LogicType.OR, MatchType.Positive);
        super.put(bizCondition);
        return this;
    }

    /**
     * 自定义查询条件
     * 
     * @param condition 条件对象
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotBizCondition(WhereCondition condition) {
        BizCondition bizCondition = new BizCondition(condition, LogicType.OR, MatchType.Negative);
        super.put(bizCondition);
        return this;
    }

    /**
     * 等于条件<br>
     * [SQL] AND fieldName = fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andEqualsIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, "=", fieldValue);
    }

    /**
     * 不等于条件<br>
     * [SQL] AND fieldName != fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotEqualsIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, "!=", fieldValue);
    }

    /**
     * 小于条件<br>
     * [SQL] AND fieldName < fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLessThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, "<", fieldValue);
    }

    /**
     * 小于等于条件<br>
     * [SQL] AND fieldName <= fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLessEqualsThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, "<=", fieldValue);
    }

    /**
     * 大于条件<br>
     * [SQL] AND fieldName > fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andGreaterThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, ">", fieldValue);
    }

    /**
     * 大于等于条件<br>
     * [SQL] AND fieldName >= fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andGreaterEqualsThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.andIf(asserts, fieldName, ">=", fieldValue);
    }

    /**
     * IS NULL条件<br>
     * [SQL] AND fieldName IS NULL
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIsNullIf(boolean asserts, String fieldName) {
        return this.andIf(asserts, fieldName, "is null");
    }

    /**
     * IS NOT NULL条件<br>
     * [SQL] AND fieldName IS NOT NULL
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andIsNotNullIf(boolean asserts, String fieldName) {
        return this.andIf(asserts, fieldName, "is not null");
    }

    /**
     * LIKE条件<br>
     * [ORACLE/DB2] AND fieldName LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] AND fieldName LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找带有%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLikeIf(String, LikeValue)
     */
    public DbWhere andLikeIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "like", fieldValue);
    }

    /**
     * LIKE条件<br>
     * AND fieldName LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: andLike("code", new LikeValue('#', "%10#%"));表示查找以10%结尾的数据<br>
     * 如: andLike("code", new LikeValue("%HOT%COOL%"));表示查找含有HOT和COOL的数据<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andLikeIf(boolean asserts, String fieldName, LikeValue fieldValue) {
        return this.andIf(asserts, fieldName, "like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不包含%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLikeIf(String, LikeValue)
     */
    public DbWhere andNotLikeIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "not like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * AND fieldName NOT LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: andNotLike("code", new LikeValue('#', "%10#%"));表示查找不以10%结尾的数据<br>
     * 如: andNotLike("code", new LikeValue("%HOT%COOL%"));表示查找不含有HOT和COOL的数据<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotLikeIf(boolean asserts, String fieldName, LikeValue fieldValue) {
        return this.andIf(asserts, fieldName, "not like", fieldValue);
    }

    /**
     * LIKE前缀查询条件<br>
     * [ORACLE/DB2] AND fieldName LIKE(fieldValue||'%')<br>
     * [MYSQL] AND fieldName LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLikeIf(String, LikeValue)
     */
    public DbWhere andStartsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "starts", fieldValue);
    }

    /**
     * NOT LIKE前缀查询条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE(fieldValue||'%')<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLikeIf(String, LikeValue)
     */
    public DbWhere andNotStartsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "not starts", fieldValue);
    }

    /**
     * LIKE后缀查询条件<br>
     * [ORACLE/DB2] AND fieldName LIKE('%'||fieldValue)<br>
     * [MYSQL] AND fieldName LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andLikeIf(String, LikeValue)
     */
    public DbWhere andEndsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "ends", fieldValue);
    }

    /**
     * NOT LIKE后缀查询条件<br>
     * [ORACLE/DB2] AND fieldName NOT LIKE('%'||fieldValue)<br>
     * [MYSQL] AND fieldName NOT LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #andNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #andNotLikeIf(String, LikeValue)
     */
    public DbWhere andNotEndsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.andIf(asserts, fieldName, "not ends", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] AND fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andInIf(boolean asserts, String fieldName, Collection<?> fieldValue) {
        return this.andIf(asserts, fieldName, "in", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] AND fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andInIf(boolean asserts, String fieldName, Object... fieldValue) {
        return this.andIf(asserts, fieldName, "in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] AND fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotInIf(boolean asserts, String fieldName, Collection<?> fieldValue) {
        return this.andIf(asserts, fieldName, "not in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] AND fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotInIf(boolean asserts, String fieldName, Object... fieldValue) {
        return this.andIf(asserts, fieldName, "not in", fieldValue);
    }

    /**
     * BETWEEN查询条件<br>
     * [SQL] AND fieldName BETWEEN startValue AND endValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andBetweenIf(boolean asserts, String fieldName, Object startValue, Object endValue) {
        return this.andIf(asserts, fieldName, "between", startValue, endValue);
    }

    /**
     * NOT BETWEEN查询条件<br>
     * [SQL] AND fieldName NOT BETWEEN startValue AND endValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere andNotBetweenIf(boolean asserts, String fieldName, Object startValue, Object endValue) {
        return this.andIf(asserts, fieldName, "not between", startValue, endValue);
    }

    /**
     * 等于条件<br>
     * [SQL] OR fieldName = fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orEqualsIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, "=", fieldValue);
    }

    /**
     * 不等于条件<br>
     * [SQL] OR fieldName != fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotEqualsIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, "!=", fieldValue);
    }

    /**
     * 小于条件<br>
     * [SQL] OR fieldName < fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLessThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, "<", fieldValue);
    }

    /**
     * 小于等于条件<br>
     * [SQL] OR fieldName <= fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLessEqualsThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, "<=", fieldValue);
    }

    /**
     * 大于条件<br>
     * [SQL] OR fieldName > fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orGreaterThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, ">", fieldValue);
    }

    /**
     * 大于等于条件<br>
     * [SQL] OR fieldName >= fieldValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orGreaterEqualsThenIf(boolean asserts, String fieldName, Object fieldValue) {
        return this.orIf(asserts, fieldName, ">=", fieldValue);
    }

    /**
     * IS NULL条件<br>
     * [SQL] OR fieldName IS NULL
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIsNullIf(boolean asserts, String fieldName) {
        return this.orIf(asserts, fieldName, "is null");
    }

    /**
     * IS NOT NULL条件<br>
     * [SQL] OR fieldName IS NOT NULL
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orIsNotNullIf(boolean asserts, String fieldName) {
        return this.orIf(asserts, fieldName, "is not null");
    }

    /**
     * LIKE条件<br>
     * [ORACLE/DB2] OR fieldName LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] OR fieldName LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找带有%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLikeIf(String, LikeValue)
     */
    public DbWhere orLikeIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "like", fieldValue);
    }

    /**
     * LIKE条件<br>
     * OR fieldName LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: orLike("code", new LikeValue('#', "%10#%"));表示查找以10%结尾的数据<br>
     * 如: orLike("code", new LikeValue("%HOT%COOL%"));表示查找含有HOT和COOL的数据<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orLikeIf(boolean asserts, String fieldName, LikeValue fieldValue) {
        return this.orIf(asserts, fieldName, "like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE('%'||fieldValue||'%')<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT('%',fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不包含%的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLikeIf(String, LikeValue)
     */
    public DbWhere orNotLikeIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "not like", fieldValue);
    }

    /**
     * NOT LIKE条件<br>
     * OR fieldName NOT LIKE fieldValue ESCAPE escapeChar<br>
     * 如果传入了escapeChar, 将会自动生成带ESCAPE的SQL<br>
     * 如: orNotLike("code", new LikeValue('#', "%10#%"));表示查找不以10%结尾的数据<br>
     * 如: orNotLike("code", new LikeValue("%HOT%COOL%"));表示查找不含有HOT和COOL的数据<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值 (带escapeChar和通配符的LikeValue)
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotLikeIf(boolean asserts, String fieldName, LikeValue fieldValue) {
        return this.orIf(asserts, fieldName, "not like", fieldValue);
    }

    /**
     * LIKE前缀查询条件<br>
     * [ORACLE/DB2] OR fieldName LIKE(fieldValue||'%')<br>
     * [MYSQL] OR fieldName LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLikeIf(String, LikeValue)
     */
    public DbWhere orStartsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "starts", fieldValue);
    }

    /**
     * NOT LIKE前缀查询条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE(fieldValue||'%')<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT(fieldValue,'%')<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%开头的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLikeIf(String, LikeValue)
     */
    public DbWhere orNotStartsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "not starts", fieldValue);
    }

    /**
     * LIKE后缀查询条件<br>
     * [ORACLE/DB2] OR fieldName LIKE('%'||fieldValue)<br>
     * [MYSQL] OR fieldName LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orLikeIf(String, LikeValue)
     */
    public DbWhere orEndsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "ends", fieldValue);
    }

    /**
     * NOT LIKE后缀查询条件<br>
     * [ORACLE/DB2] OR fieldName NOT LIKE('%'||fieldValue)<br>
     * [MYSQL] OR fieldName NOT LIKE CONCAT('%',fieldValue)<br>
     * 如果fieldValue中包含%等特殊字符, 只会当作普通字符处理, 就表示查找不以%结尾的数据, 将会自动生成带ESCAPE的SQL<br>
     * 如果希望自己处理ESCAPE逻辑, 可使用{@link #orNotLikeIf(String, LikeValue)}方法<br>
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     * @see #orNotLikeIf(String, LikeValue)
     */
    public DbWhere orNotEndsIf(boolean asserts, String fieldName, String fieldValue) {
        return this.orIf(asserts, fieldName, "not ends", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] OR fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orInIf(boolean asserts, String fieldName, Collection<?> fieldValue) {
        return this.orIf(asserts, fieldName, "in", fieldValue);
    }

    /**
     * IN查询条件<br>
     * [SQL] OR fieldName IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orInIf(boolean asserts, String fieldName, Object... fieldValue) {
        return this.orIf(asserts, fieldName, "in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] OR fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotInIf(boolean asserts, String fieldName, Collection<?> fieldValue) {
        return this.orIf(asserts, fieldName, "not in", fieldValue);
    }

    /**
     * NOT IN查询条件<br>
     * [SQL] OR fieldName NOT IN (fieldValue1, fieldValue2, ...)
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotInIf(boolean asserts, String fieldName, Object... fieldValue) {
        return this.orIf(asserts, fieldName, "not in", fieldValue);
    }

    /**
     * BETWEEN查询条件<br>
     * [SQL] OR fieldName BETWEEN startValue AND endValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orBetweenIf(boolean asserts, String fieldName, Object startValue, Object endValue) {
        return this.orIf(asserts, fieldName, "between", startValue, endValue);
    }

    /**
     * NOT BETWEEN查询条件<br>
     * [SQL] OR fieldName NOT BETWEEN startValue AND endValue
     * 
     * @param asserts 判断条件, 只有asserts=true才添加查询条件
     * @param fieldName 字段名
     * @param startValue 开始字段值
     * @param endValue 结束字段值
     * @return 返回容器自身, 用于链式操作
     */
    public DbWhere orNotBetweenIf(boolean asserts, String fieldName, Object startValue, Object endValue) {
        return this.orIf(asserts, fieldName, "not between", startValue, endValue);
    }

    public static interface SubCondition {

        void build(DbWhere where);
    }

    public static class BizCondition implements DbCondition, LogicCondition, MatchCondition {

        private final WhereCondition condition;
        /** 逻辑联连类型: AND / OR **/
        private final LogicType logicType;
        /** 匹配模式 **/
        private final MatchType matchType;

        public BizCondition(WhereCondition condition, LogicType logicType, MatchType matchType) {
            this.condition = condition;
            this.logicType = logicType;
            this.matchType = matchType;
        }

        public WhereCondition getWhereCondition() {
            return condition;
        }

        /** 逻辑联连类型: AND / OR **/
        @Override
        public LogicType getLogicType() {
            return logicType;
        }

        /** 匹配模式 **/
        @Override
        public MatchType getMatchType() {
            return matchType;
        }

        @Override
        public boolean isEmpty() {
            return condition == null ? true : condition.isEmpty();
        }
    }

    /**
     * 通过字段对象列表构造DbWhere对象
     * 
     * @param <T> DbWhere泛型
     * @param fields 字段对象
     * @param instanceType 实例类型
     * @return DbWhere对象
     */
    public static <T extends DbWhere> T ofFields(List<DbField> fields, Class<T> instanceType) {
        VerifyTools.requireNonNull(instanceType, "class");
        T instance;
        try {
            instance = instanceType.newInstance();
        } catch (InstantiationException e) {
            throw new IllegalStateException("Failed to new instance for " + instanceType.getName(), e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Failed to new instance for " + instanceType.getName(), e);
        }
        if (fields != null && !fields.isEmpty()) {
            for (DbField field : fields) {
                instance.put(field);
            }
        }
        return instance;
    }

    public class Field extends DbField implements LogicCondition {

        /** serialVersionUID **/
        private static final long serialVersionUID = 1L;

        private final DbWhere container;
        private final LogicType logicType;

        /** 构造函数 **/
        public Field(LogicType logicType) {
            this.logicType = logicType;
            this.container = DbWhere.this;
        }

        /** 构造函数 **/
        private Field(LogicType logicType, DbField field) {
            super(field.getOperateType(), field.getFieldName(), field.getFieldValue());
            this.container = DbWhere.this;
            this.logicType = logicType;
        }

        /** 构造函数 **/
        public Field(LogicType logicType, String fieldName, Object fieldValue) {
            super(fieldName, fieldValue);
            this.container = DbWhere.this;
            this.logicType = logicType;
        }

        /** 构造函数 **/
        public Field(LogicType logicType, String operateType, String fieldName, Object fieldValue) {
            super(operateType, fieldName, fieldValue);
            this.container = DbWhere.this;
            this.logicType = logicType;
        }

        public DbWhere getContainer() {
            return container;
        }

        @Override
        public LogicType getLogicType() {
            return logicType;
        }

        @Override
        public Field copy() {
            LogicType logicType = this.getLogicType();
            String operateType = this.getOperateType();
            String fieldName = this.getFieldName();
            Object fieldValue = this.getFieldValue();
            return new Field(logicType, operateType, fieldName, fieldValue);
        }
    }

    private static class InnerSubWhere extends SubWhere {

        /** SerialVersionUID **/
        private static final long serialVersionUID = 1L;

        private LogicType innerLogicType;

        protected InnerSubWhere() {
            super();
        }

        public InnerSubWhere(DbWhere parent, LogicType logicType, MatchType matchType, LogicType innerLogicType) {
            super(parent, logicType, matchType);
            this.innerLogicType = innerLogicType;
        }

        @Override
        public SubWhere on(String fieldName, String operate, Object... fieldValues) {
            if (innerLogicType == LogicType.OR) {
                this.or(fieldName, operate, fieldValues);
            } else {
                this.and(fieldName, operate, fieldValues);
            }
            return this;
        }

        /** 增加自定义条件 **/
        @Override
        public SubWhere on(WhereCondition condition) {
            if (innerLogicType == LogicType.OR) {
                super.orBizCondition(condition);
            } else {
                super.andBizCondition(condition);
            }
            return this;
        }

        /** {@inheritDoc} **/
        @Override
        public InnerSubWhere copy() {
            InnerSubWhere copies = newCopies();
            this.copyTo(copies);
            return copies;
        }

        protected void copyTo(InnerSubWhere copies) {
            super.copyTo(copies);
            copies.innerLogicType = this.innerLogicType;
        }

        /** {@inheritDoc} **/
        @Override
        protected InnerSubWhere newCopies() {
            if (this.getClass() == InnerSubWhere.class) { // 当前类
                return new InnerSubWhere();
            } else { // 子类
                try {
                    return this.getClass().newInstance();
                } catch (Exception e) {
                    throw new IllegalStateException("CloneNotSupported, FailedToInvokeDefaultConstructor.");
                }
            }
        }
    }

    /**
     * 允许为空的查询条件
     *
     * @author zhaohuihua
     * @version 20200206
     */
    public static class EmptiableWhere extends DbWhere {

        /** serialVersionUID **/
        private static final long serialVersionUID = 1L;
    }

    /**
     * 只读Where条件
     *
     * @author zhaohuihua
     * @version 190310
     */
    private static class ReadonlyWhere extends EmptiableWhere {

        /** serialVersionUID **/
        private static final long serialVersionUID = 1L;

        private ReadonlyWhere() {
        }

        @Override
        public ReadonlyWhere copy() {
            return this;
        }

        @Override
        protected void put(String fieldName, Object fieldValue) {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        protected void put(String operateType, String fieldName, Object fieldValue) {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        protected void put(DbField condition) {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        protected void put(DbConditions fields) {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        protected void put(DbCondition condition) {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        public void clear() {
            throw new UnsupportedOperationException("read only");
        }

        @Override
        public SubWhere sub(String operate) {
            throw new UnsupportedOperationException("read only");
        }

    }
}
